/******************************
 * @Developer: many
 * @File: optionpre.go
 * @Time: 2022/5/13 11:36
******************************/

package fixopt

import (
	"fmt"
	"reflect"
	"strings"
)

type Field struct {
	up    bool
	name  string
	value interface{}
}

func (self *Field) fixFiled(option interface{}) error {
	reftype := reflect.TypeOf(option)
	refvalue := reflect.ValueOf(option)
	if reftype.Kind() != reflect.Ptr {
		return fmt.Errorf("invalid fixopt carrier")
	}

	for i := 0; i < reftype.Elem().NumField(); i++ {
		temp := reftype.Elem().Field(i)
		value := refvalue.Elem().Field(i)
		if strings.ToLower(temp.Name) == self.name {
			i = reftype.Elem().NumField()
			value.Set(reflect.ValueOf(self.value))

			return nil
		}
	}

	for i := 0; i < reftype.NumMethod(); i++ {
		temp := reftype.Method(i)
		if strings.ToLower(temp.Name) == self.name {
			i = reftype.NumMethod()
			result := temp.Func.Call([]reflect.Value{refvalue, reflect.ValueOf(self.value)})
			if len(result) == 1 && result[0].Interface() != nil {
				return result[0].Interface().(error)
			}

			return nil
		}
	}

	return nil
}

func WithField(opt string, value interface{}) *Field {
	return &Field{name: opt, value: value}
}

func FixOptions(option interface{}, opts ...*Field) error {
	for _, opt := range opts {
		if err := opt.fixFiled(option); err != nil {
			return err
		}
	}

	return nil
}
